package org.cresource.user.service.impl;


import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.cresource.basic.constant.VerifyCodeContants;
import org.cresource.basic.constant.WxConstants;
import org.cresource.basic.exception.BusinessException;
import org.cresource.basic.util.AjaxResult;
import org.cresource.basic.util.HttpClientUtils;
import org.cresource.basic.util.MD5Utils;
import org.cresource.basic.util.StrUtils;
import org.cresource.user.domain.*;
import org.cresource.user.mapper.LoginInfoMapper;
import org.cresource.user.mapper.UserMapper;
import org.cresource.user.mapper.WxUserMapper;
import org.cresource.user.service.ILoginService;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * 统一登录业务层
 */
@Service
@Transactional(readOnly = true,propagation = Propagation.SUPPORTS)
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private  LoginInfoMapper logininfoMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private WxUserMapper wxUserMapper;


    /**
     * 绑定授权
     */
    @Override
    public AjaxResult binder(Map<String, String> map) {
        String accessToken = map.get("accessToken");
        String openId = map.get("openId");
        String phone = map.get("phone");
        String verifyCode = map.get("verifyCode");
        // 空校验
        if(StringUtils.isEmpty(accessToken) ||
           StringUtils.isEmpty(openId)||
           StringUtils.isEmpty(phone) ||
           StringUtils.isEmpty(verifyCode)){
            return AjaxResult.me().setMessage("必要参数为空！");
        }
        //验证码校验
        Object o = redisTemplate.opsForValue().get(VerifyCodeContants.USER_BINDING_CODE + ":" + phone);
        //为空 证明验证码失效了
        if (o==null){
            return AjaxResult.me().setMessage("验证码失效咯！");
        }
        String code = ((String) o).split(":")[0];
        //不为空 验证验证码是否一样
        if (!verifyCode.equalsIgnoreCase(code)){
            return AjaxResult.me().setMessage("验证码不对哦！");
        }
        //请求微信数据  拼接请求
        String userUrl = WxConstants.GET_USER_URL
                         .replace("ACCESS_TOKEN",accessToken )
                         .replace("OPENID", openId);
        //用工具类去微信拿信息
        String s = HttpClientUtils.httpGet(userUrl);
        //判断有无信息 微信反馈扫码人是否真实
        if (s==null){
            return AjaxResult.me().setMessage("微信用户不存在！");
        }

        //用手机号查询logininfo表信息
        UserDto userDto = new UserDto();
        userDto.setPhone(phone);
        userDto.setType(0);
        //用userDto查询loginInfo信息
        LoginInfo loginInfo=logininfoMapper.loadByUserDto(userDto);
        User user = new User();

        //不为空 证明用手机登录过 直接绑定之前的
        if (loginInfo!=null){
          //如果不为空 证明有user表和logininfo表 只需要加wxuser的 wxuser需要userid
             user= userMapper.loadByloingInfoId(loginInfo.getId());
        }
        //为空 证明新用户 创建一个新用户绑定
        else {
          //为空 就需要创建3个表信息
            //通过电话创建logininfo信息
            LoginInfo loginInfo1=createLoginInfo(phone);
            //logininfo转换为user信息
            user=loginInfo2user(loginInfo1);
            //保存logininfo表
            logininfoMapper.save(loginInfo1);
            //保存user表
            user.setInfo(loginInfo1);
            userMapper.save(user);
        }
        System.out.println("---------------------------------"+user);
        // 把user的信息放到wxuser中
        WxUser wxUser=user2WxUser(s,user);
        wxUser.setUser_id(user.getId());
        //保存wxuser表
        System.out.println("---------------------------------"+wxUser);
        wxUserMapper.save(wxUser);

        //登录成功免密登录
        LoginInfo  logininfo= logininfoMapper.loadByUserId(wxUser.getUser_id());
        String token = UUID.randomUUID().toString();
        //toke是uuid数 唯一 存的value是信息
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
        //封装返回给前端
        Map<String,Object> map1= new HashMap<>();
        map1.put("token", token);
        //高级程序员素养 不能把账号密码还回去
        logininfo.setUsername("");
        logininfo.setPassword("");
        map1.put("logininfo",logininfo);
        return AjaxResult.me().setResultObj(map1);
    }



    //电话创建logininfo对象
    private LoginInfo createLoginInfo(String phone) {
        LoginInfo info = new LoginInfo();
        info.setUsername(phone);
        info.setPhone(phone);
        //设置一个默认密码
        String salt = StrUtils.getComplexRandomString(32);
        String md5Pwd = MD5Utils.encrypByMd5(StrUtils.getComplexRandomString(6) + salt);
        info.setSalt(salt);
        info.setPassword(md5Pwd);
        return info;
    }


    private User loginInfo2user(LoginInfo info) {
        User user = new User();
        BeanUtils.copyProperties(info,user);//根据同名原则拷贝
        return user;
    }


    private WxUser user2WxUser(String wxUserStr, User user) {
        //装换微信用户信息
        JSONObject jsonObject = JSONObject.parseObject(wxUserStr);
        WxUser wxUser =  new WxUser();
        wxUser.setUser_id(user.getId());//绑定平台用户
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        return wxUser;
    }






































    //微信登录
    @Override
    public AjaxResult wechat(Map<String, String> map) {

        //空校验
        String code = map.get("code");
        String binderUrl = map.get("binderUrl");
        if(StringUtils.isEmpty(code) ||
           StringUtils.isEmpty(binderUrl)){
            return AjaxResult.me().setMessage("必要参数为空！");
        }
        //去微信拿token  这个是获取的地址
        String accessTokenUrl = WxConstants.GET_ACK_URL
                .replace("APPID", WxConstants.APPID)
                .replace("SECRET", WxConstants.SECRET)
                .replace("CODE", code);

        //拿到token数据
        String strobj = HttpClientUtils.httpGet(accessTokenUrl);
        //转json
        JSONObject jsonObject = JSONObject.parseObject(strobj);
        String accessToken = (String) jsonObject.get("access_token");
        String accessOpenid = (String) jsonObject.get("openid");
        //通过openid获得wxuser
        WxUser wxUser = wxUserMapper.loadByOpenId(accessOpenid);
        //老用户了 wx和user都有
        if (wxUser!=null&&wxUser.getUser_id()!=null){


            LoginInfo  logininfo= logininfoMapper.loadByUserId(wxUser.getUser_id());
            String token = UUID.randomUUID().toString();
            //toke是uuid数 唯一 存的value是信息
            redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);
            //封装返回给前端
            Map<String,Object> map1= new HashMap<>();
            map1.put("token", token);
            //高级程序员素养 不能把账号密码还回去
            logininfo.setUsername("");
            logininfo.setPassword("");
            map1.put("logininfo",logininfo);
            return AjaxResult.me().setResultObj(map1);
        }else {
            String resultUrl=binderUrl+"?access_Token="+accessToken+"&openid="+accessOpenid;
            return AjaxResult.me().setSuccess(false).setResultObj(resultUrl);



        }


    }




    /**
     * 账号登录  s层
     * loginDto 中表明了是哪一个端登录 type = 0
     */
    @Override
    public AjaxResult account(LoginDto loginDto) {
        //1.校验
        // 1.1 空校验  loginDto所有字段都要校验
        if(StringUtils.isEmpty(loginDto.getUsername()) ||
                StringUtils.isEmpty(loginDto.getPassword()) ||
                StringUtils.isEmpty(loginDto.getType()) ){
            return AjaxResult.me().setMessage("用户或密码不能为空！");
        }
        // 1.2 判断用户是否存在  查询logininfo表
        LoginInfo logininfo = logininfoMapper.loadByLoginDto(loginDto);
        if (logininfo == null) {
            return AjaxResult.me().setMessage("用户不存在！");
        }
        // 1.3 账号是否被禁用
        if(logininfo.getDisable() != 1){
            return AjaxResult.me().setMessage("账号被禁用，请联系管理员！");
        }
        // 2.判断密码是否正确
        String salt = logininfo.getSalt();
        String md5pwd = logininfo.getPassword();
        String md5PwdTmp = MD5Utils.encrypByMd5(loginDto.getPassword()+salt);
        if(!md5pwd.equals(md5PwdTmp)){
            // 2.2 密码不等  抛错
            return AjaxResult.me().setMessage("密码错误！");
        }
        // 2.1 如果密码相等  登录成功  存redis，封装返回值
        // 这里的redis  key就是前端需要存储的token
        String token = UUID.randomUUID().toString();


        //判断type决定是前端登录还是后台登录

        //toke是uuid数 唯一 存的value是信息
        redisTemplate.opsForValue().set(token, logininfo, 30, TimeUnit.MINUTES);





        //封装返回给前端
        Map<String,Object> map = new HashMap<>();
        map.put("token", token);
        //高级程序员素养 不能把账号密码还回去
        logininfo.setUsername("");
        logininfo.setPassword("");
        map.put("logininfo",logininfo);
        return AjaxResult.me().setResultObj(map);
    }


}
